package cn.yaoud.salus.imexport.processor;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.listener.ReadListener;

import cn.yaoud.salus.imexport.component.StreamImportListener;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

/**
 * The `ImportProcessor` class is designed to handle the import of data from an Excel file using the EasyExcel library.
 * It provides functionality to read data from an Excel file, process it in chunks, and register listeners to handle the
 * data as it is read. The class supports customization of the number of rows read at a time, the sheet number, and the
 * starting line number for reading data.
 *
 * <p>
 * The class is annotated with Lombok annotations (`@Data`, `@Builder`, `@AllArgsConstructor`) to automatically generate
 * getters, setters, constructors, and builder methods.
 * </p>
 *
 * <p>
 * Key features of the `ImportProcessor` class include:
 * </p>
 * <ul>
 * <li>Reading data from an Excel file using an `InputStream`.</li>
 * <li>Support for customizing the number of rows read at a time, with a default value of 1000 rows.</li>
 * <li>Registering listeners to process data as it is read from the Excel file.</li>
 * <li>Support for reading from a specific sheet and starting line number within the Excel file.</li>
 * <li>Tracking the number of rows processed and successfully handled.</li>
 * <li>Closing the Excel reader to release resources after processing is complete.</li>
 * </ul>
 *
 * <p>
 * The class provides static methods to initialize an `ImportProcessor` instance with an `InputStream` and a class
 * representing the data model. It also allows for the registration of data listeners that implement the
 * `StreamImportListener` interface.
 * </p>
 *
 * <p>
 * Example usage:
 * </p>
 * 
 * <pre>
 * InputStream inputStream = ...; // Obtain an InputStream from a file or other source
 * Class<?> clazz = MyDataModel.class; // Define the class representing the data model
 * ImportProcessor processor = ImportProcessor.init(inputStream, clazz);
 * processor.registerDataListener(new MyDataListener());
 * processor.read();
 * processor.close();
 * </pre>
 *
 * <p>
 * Note: The class includes commented-out code for additional functionality, such as reading from an OSS file or
 * updating the progress of a task. These features are not currently implemented but could be extended in the future.
 * </p>
 *
 * <p>
 * This class is thread-safe for reading operations, but care should be taken when modifying shared state such as the
 * `hasProcessedNum` and `successedNum` fields.
 * </p>
 */
@Data
@Builder
@AllArgsConstructor
public class ImportProcessor {

    private InputStream inputStream;

    private Class<?> clazz;

    private Integer singleReadRowNum;

    private Long hasProcessedNum;
    private Long successedNum;

    // private Long taskId;

    // 默认一次读1000行
    private static final Integer DEFAULT_READ_ROW_NUM = 1000;

    public static final Integer DEFAULT_SHEET_NO = 1;
    public static final Integer DEFAULT_START_LINE_NO = 2;

    private List<ReadListener<?>> readListenerList = new ArrayList();

    private ExcelReader excelReader;

    public ImportProcessor() {

    }

    /*    public static ImportProcessor init(String ossfileUrl, Class<?> clazz) {
        S3ObjectInputStream s3ObjectInputStream = OssUtils.readOssFile(ossfileUrl);
        return init(s3ObjectInputStream.getDelegateStream(), clazz);
    }
    
    public static ImportProcessor init(File file, Class<?> clazz) throws IOException {
        return init(Files.newInputStream(file.toPath()), clazz);
    }*/

    /**
     * 初始化导入对象
     *
     * @param 文件流
     * @param 解析对象
     * @return
     */
    public static ImportProcessor init(InputStream stream, Class<?> clazz) {
        ImportProcessor importProcessor = new ImportProcessor();
        importProcessor.setClazz(clazz);
        importProcessor.setInputStream(stream);
        return importProcessor;
    }

    public ImportProcessor registerDataListener(StreamImportListener<?> streamImportListener) {
        if (singleReadRowNum == null || singleReadRowNum > DEFAULT_READ_ROW_NUM) {
            singleReadRowNum = DEFAULT_READ_ROW_NUM;
        }
        streamImportListener.init(singleReadRowNum, this);
        readListenerList.add(streamImportListener);
        return this;
    }

    public void read() {
        read(DEFAULT_SHEET_NO, DEFAULT_START_LINE_NO);
    }

    /**
     * 读取数据
     * 
     * @param readStartLineNo
     *            读取起始行 excel表的真实行号,不需要-1
     */
    public void read(Integer readStartLineNo) {
        excelReader = EasyExcelFactory.read(inputStream).build();
        excelReader.read(EasyExcelFactory.readSheet().headRowNumber(readStartLineNo - 1).head(clazz)
            .registerReadListener(readListenerList.get(0)).build());
    }

    /**
     * 读取数据
     *
     * @param sheetNo
     *            读取的sheet页码 从1开始
     * @param readStartLineNo
     *            读取起始行 excel表的真实行号,不需要-1
     */

    public void read(Integer sheetNo, Integer readStartLineNo) {
        excelReader = EasyExcelFactory.read(inputStream).build();
        excelReader.read(EasyExcelFactory.readSheet(sheetNo - 1).headRowNumber(readStartLineNo - 1).head(clazz)
            .registerReadListener(readListenerList.get(0)).build());
    }

    private void refresh(Long hasProcessedNum, Long successedNum) {
        this.hasProcessedNum = hasProcessedNum;
        this.successedNum = successedNum;
        /*        if (taskId != null) {
             OssUtils.updateProcess(taskId, successedNum, hasProcessedNum);
        }*/

    }

    public void close() {
        if (null != excelReader) {
            excelReader.finish();
        }
    }

    public void setSingleReadRowNum(Integer singleReadRowNum) {
        if (singleReadRowNum == null || singleReadRowNum > DEFAULT_READ_ROW_NUM) {
            throw new RuntimeException("单次读取行数不能大于1000");
        }
        this.singleReadRowNum = singleReadRowNum;
    }
}
